home *** CD-ROM | disk | FTP | other *** search
- /* HyperCard XFCN that takes a target string and returns the key record
- * number just above it in the (already opened) key file F ... called as:
- * jumpKey ( S, M, F)
- * where S is the string, M is the maximum key_rec_number (0-based, so
- * thus it's one less than the total number of distinct words in the file),
- * and F is a refNum value returned by the XFCN openFile().
- *
- * The results are returned as a 0-terminated string consisting of the
- * key record number (in ASCII) at or just before the input string.
- *
- * If there has been a mistake, a null string is returned and the function
- * also emits a beep....
- *
- * The function works by taking the input string, turning any lower-case
- * letters into capitals, and then does a binary search on the key file.
- *
- * The external function is stored as XFCN number 851, named "jumpKey"....
- *
- * The key file must in the standard ^z browser format as created
- * by qndxr, etc....
- *
- * 871211 ^z
- */
-
- #include <MacTypes.h>
- #include <FileMgr.h>
- #include <OSUtil.h>
- #include <HyperXCmd.h>
- #include <proto.h>
-
- #define KEY_LENGTH 28 /* default choice in building indices */
- typedef struct
- {
- char kkey[KEY_LENGTH];
- long ccount;
- } KEY_REC;
-
-
- pascal void main (XCmdBlockPtr paramPtr);
- void getKeyRec (KEY_REC *recp, long recNum, int refNum);
- int putNum (char *ans, long count);
- void complain (XCmdBlockPtr paramPtr);
- void init_target (KEY_REC *target, char *inputTarget);
- int zstrcmp (char *s1, char *s2);
-
- pascal void main (paramPtr)
- XCmdBlockPtr paramPtr;
- {
- KEY_REC thisRec, targetRec;
- int refNum, diff, i;
- long thisRecNum, maxRecNum, low, high;
- Handle answer;
-
- if (paramPtr->paramCount != 3)
- {
- complain (paramPtr);
- return;
- }
-
- init_target (&targetRec, *(paramPtr->params[0]));
- maxRecNum = atol (*(paramPtr->params[1]));
- refNum = atol (*(paramPtr->params[2]));
-
- if (targetRec.kkey[0] == ' ' || refNum == 0)
- {
- complain (paramPtr);
- return;
- }
-
- low = 0;
- high = maxRecNum;
-
- while (low <= high)
- {
- thisRecNum = (low + high) / 2;
- getKeyRec (&thisRec, thisRecNum, refNum);
- diff = zstrcmp (targetRec.kkey, thisRec.kkey);
- if (diff < 0)
- high = thisRecNum - 1;
- else if (diff > 0)
- low = thisRecNum + 1;
- else
- break;
- }
-
- if (diff < 0)
- --thisRecNum;
- if (thisRecNum < 0)
- thisRecNum = 0;
- if (diff != 0)
- SysBeep (10);
-
- answer = NewHandle (16);
- i = putNum (*answer, thisRecNum);
- *(*answer + i) = '\0';
- paramPtr->returnValue = answer;
- return;
- }
-
-
- /* function to fetch the requested index record from the file ...
- * note that if an illegal recNum is asked for, it
- * returns 0 for ccount and a blank kkey....
- */
-
- void getKeyRec (recp, recordNum, refNum)
- KEY_REC *recp;
- long recordNum;
- int refNum;
- {
- long count;
- int i;
-
- count = sizeof(KEY_REC);
-
- if (recordNum < 0 ||
- SetFPos (refNum, fsFromStart,
- recordNum * sizeof(KEY_REC)) != noErr ||
- FSRead (refNum, &count, recp) != noErr)
- {
- for (i = 0; i < KEY_LENGTH; ++i)
- recp->kkey[i] = ' ';
- recp->ccount = 0;
- }
-
- return;
- }
-
-
-
- /* function to convert a number into a string and put it into the chosen
- * target place ... returns the number of characters stored ...
- * based on K&R p. 60 example of itoa()....
- */
-
- int putNum (ans, num)
- char *ans;
- long num;
- {
- int i, j, s, result;
-
- i = 0;
- s = 1;
- if (num < 0)
- {
- num = -num;
- s = -1;
- }
-
- do
- ans[i++] = num % 10 + '0';
- while ((num /= 10) > 0);
-
- if (s < 0)
- ans[i++] = '-';
- result = i;
-
- for (--i, j = 0; j < i; ++j, --i)
- {
- s = ans[i];
- ans[i] = ans[j];
- ans[j] = s;
- }
-
- return (result);
- }
-
-
- /* function to beep and set the return string to null (= "")
- */
-
- void complain (paramPtr)
- XCmdBlockPtr paramPtr;
- {
- Handle answer;
-
- SysBeep (10);
- answer = NewHandle (1);
- **answer = '\0';
- paramPtr->returnValue = answer;
- return;
- }
-
-
-
- /* function to convert alphabetic string to a long integer ... from LSC
- * library.... simplified to avoid using isspace() & isdigit() ....
- */
-
- long atol (s)
- register char *s;
- {
- register char signflag = 0;
- register long r = 0;
-
- while ((*s == ' '))
- s++;
-
- if (*s == '-')
- {
- signflag = 1;
- s++;
- }
- else if (*s == '+')
- s++;
-
- while (*s >= '0' && *s <= '9')
- r = r * 10 + (*s++ - '0');
-
- return (signflag ? -r : r);
- }
-
-
- /* function to initialize the target key record kkey string ... turn the
- * input target string (0-delimited) into all caps and pad to length
- * KEY_LENGTH with blanks....
- */
-
- void init_target (target, inputTarget)
- KEY_REC *target;
- char *inputTarget;
- {
- register int i, c;
-
- for (i = 0; i < KEY_LENGTH; ++i)
- {
- c = inputTarget[i];
- if (c == '\0')
- break;
- if (c >= 'a' && c <= 'z')
- c += 'A' - 'a';
- target->kkey[i] = c;
- }
-
- for ( ; i < KEY_LENGTH; ++i)
- target->kkey[i] = ' ';
- }
-
-
- /* my function to compare two strings and give a result as to who is
- * alphabetically earlier. Note that this is almost the same as strncmp()
- * with the fixed value of KEY_LENGTH as the maximum comparison distance,
- * except that I must be sure to mask the characters to make them positive
- * (since we want to be able to handle the non-ASCII funny letters in
- * the Apple character set properly/consistently). If the masking isn't
- * done, then inconsistent results can occur with those non-ASCII chars!
- */
-
- int zstrcmp (s1, s2)
- register char *s1, *s2;
- {
- register int n = KEY_LENGTH;
-
- for ( ; --n && ((*s1 & 0xFF) == (*s2 & 0xFF)); s1++, s2++)
- if (!*s1) break;
-
- return ((*s1 & 0xFF) - (*s2 & 0xFF));
- }
-
-
-
-
-